package com.txby.common.utils.util;


import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

import com.txby.common.annotation.MysqlAutoPK;

  
/** 
 * POJO基类 
 * 用户反射实体注解
 * 包括属性字段和参数数据的对应关系
 */  
public class MyBatisReflectUtil {  
	  private transient static String newId=null;
	  private transient static boolean  isAutoId;
	   /** 
     * 用于存放POJO的列信息 
     */  
    private transient static Map<Class<?>,List<String>> columnMap = new HashMap<Class<?>, List<String>>(); 
    /**
     * 默认为实体所有性字段，请保证和数据表对应一致
     */
    private boolean isAllField=true;
    /*
     * 为注解字段的数据
     */
    private transient static Map<String,Class<?>> columnAnnotationMap = new HashMap();  
    /**
     * 当前对象实体
     */
    private transient static Object o ;
    
    private Object getObject(){
    	return this.o;
    }
    /** 
     * 获取POJO对应的表名 
     * 需要POJO中的属性定义@Table(name) 
     * @return 
     */  
    public static String tablename(Object o) {  
        Table table = o.getClass().getAnnotation(Table.class);  
        if(table != null)  
            return table.name();  
        else  
            throw new PojoStructureException("undefine POJO @Table, need Tablename(@Table(name))");  
    }  
    public static String tablename(Class clazz) {  
//    	Annotation an=clazz.getAnnotation(Table.class); 
    	Table table = (Table) clazz.getAnnotation(Table.class);  
    	if(table != null)  
    		return table.name();  
    	else  
    		throw new PojoStructureException("undefine POJO @Table, need Tablename(@Table(name))");  
    }  
      
    public MyBatisReflectUtil( ){
    	
    }
    public MyBatisReflectUtil(boolean isAllField){
    	this.isAllField=isAllField;
    	
    }
    
    
    /** 
     * 获取POJO中的主键字段名 
     * 需要定义@Id 
     * @return 
     */  
    public static String id(Object o) {  
    	Map map=getAllField(o);
    	
    /*	if(map.get("objId")!=null) {
    		return map.get("objId").toString();
    	}else if(map.get("objIdmysql")!=null){
    		return map.get("objIdmysql").toString();
    	}*/
    	if(map.get("objIdmysql")!=null) {
    		return map.get("objIdmysql").toString();
    	}else if(map.get("objId")!=null){
    		return map.get("objId").toString();
    	}
       /* for(Field field : o.getClass().getDeclaredFields()) {  
            if(field.isAnnotationPresent(Id.class))  
                return field.getName();  
        }*/  
        throw new RuntimeException("undefine POJO @Id");  
    }  
  
   
    private boolean isNull(Object o,String fieldname) {  
        try {  
        	Map map=getAllField(o);
        	List<Field> fields=null;
        	Field field=null;
        	if(map.get("fields")!=null){
        		fields=(List) map.get("fields");
        		for(Field fd:fields){
        			if(fd.getName()!=null&&fd.getName().equals(fieldname)){
        				field=fd;
        			}
        			
        		}
        	}
//            Field field = o.getClass().getDeclaredField(fieldname);  
            return isNull(o,field);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
          
        return false;  
    }  
      
    private boolean isNull(Object o,Field field) {  
        try {  
//            field.setAccessible(true); 
        	if(field==null){
        		return  true;  
        	}else{
        		return PropertyUtils.getProperty(o, field.getName()) == null;  
        	}
        } catch (Exception e) {  
            e.printStackTrace();  
        } 
          
        return false;  
    }  
      
    /** 
     * 初始实体的属性字段，用于计算类定义 
     * 需要POJO中的属性定义@Column(name) 
     */  
    public void caculationColumnList(Object o) {  
    	this.o=o;
        if(columnMap.containsKey(o.getClass()))  
            return;  
          
//        Field[] fields = o.getClass().getDeclaredFields(); 
        List<Field> fields = new ArrayList<>() ;
        List<String> columnList = new ArrayList<String>(fields.size());  
        Class tempClass =o.getClass();
    /*    while (tempClass != null&&!tempClass.getName().toLowerCase().equals("java.lang.object")) {//当父类为null的时候说明到达了最上层的父类(Object类).
        	fields.addAll(Arrays.asList(tempClass .getDeclaredFields()));
             tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
        }*/
        Map<String,Class> idAnnotation = new HashMap();
        Map<String,Class> mysqlIdAnnotation = new HashMap();
        while (tempClass != null&&!tempClass.getName().toLowerCase().equals("java.lang.object")) {//当父类为null的时候说明到达了最上层的父类(Object类).
        	Field fd[]=tempClass .getDeclaredFields();
        	fields.addAll(Arrays.asList(fd));
        	tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
        	for(Field field : fd){
        		Annotation an=field.getAnnotation(Id.class);
        		Annotation mysqlAnnotation=field.getAnnotation(MysqlAutoPK.class);
        		if(an!=null){
        			GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
        			if(gv==null||!gv.strategy().equals(GenerationType.IDENTITY)){
        				idAnnotation.put(field.getName(), Id.class);
        			}
        		}
        		if(mysqlAnnotation!=null){
        			mysqlIdAnnotation.put(field.getName(), MysqlAutoPK.class);
        		}
        	}
        }
//        System.out.println(fieldAllAnnotation);
        for(Field field : fields) { 
        /*	if(field.isAnnotationPresent(Id.class)){
            	if(!field.isAnnotationPresent(GeneratedValue.class)){
            		columnList.add(field.getName()); 
            		columnAnnotationMap.put(field.getName(), Id.class);
            	}else{
            		GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
            		//如果不是配置了数据库自增长id,则使用系统全球唯一id策略
            		if(!gv.strategy().equals(GenerationType.IDENTITY)){
            			columnList.add(field.getName()); 
                		columnAnnotationMap.put(field.getName(), Id.class);
            		}
            	}
            } */
        	if(mysqlIdAnnotation.get(field.getName())!=null){
        		columnList.add(field.getName()); 
				columnAnnotationMap.put(field.getName(), MysqlAutoPK.class);
        	}else
        	if(idAnnotation.get(field.getName())!=null){
        				columnList.add(field.getName()); 
        				columnAnnotationMap.put(field.getName(), Id.class);
        	} else  if(field.isAnnotationPresent(Column.class)){
            	columnList.add(field.getName()); 
            	columnAnnotationMap.put(field.getName(), Column.class);
            }  
        	//下面控制实体所有属性的添加
            else if(isAllField){ 
            	if(!field.getName().equals("serialVersionUID")){
            		columnList.add(field.getName()); 
            		columnAnnotationMap.put(field.getName(), Column.class);
               }
            }
        	
        	
        }  
          
        columnMap.put(o.getClass(), columnList);  
    }  
      
    /** 
     * 获取用于WHERE的 有值字段表 
     * @return 
     */  
    public List<WhereColumn> returnWhereColumnsName(Object o) {  
        Field[] fields = o.getClass().getDeclaredFields();  
        List<WhereColumn> columnList = new ArrayList<WhereColumn>(fields.length);  
        for(Field field : fields) {  
//            if((field.isAnnotationPresent(Column.class) && !isNull(o,field)))   
            	 if(!isNull(o,field))   
                columnList.add(new WhereColumn(field.getName(), field.getGenericType().equals(String.class)));  
        }  
          
        return columnList;  
    }  
      
    /** 
     * Where条件信息 
     * @author HUYAO 
     * 
     */  
    public class WhereColumn {  
        public String name;  
        public boolean isString;  
        public WhereColumn(String name,boolean isString) {  
            this.name = name;  
            this.isString = isString;  
        }  
    }  
      
    /** 
     * 用于获取Insert的字段累加 
     * @return 
     */  
    public String returnInsertColumnsName(Object o) {  
        StringBuilder sb = new StringBuilder();  
        List<String> list = columnMap.get(o.getClass()); 
        int i = 0;  
        for(String column : list) {  
         	boolean isId=false;
//        	System.out.println("长"+columnAnnotationMap.get(column).getName());
         	
//         	增加mysql自增整型主键的处理
         	if(columnAnnotationMap.get(column).getName().equals(MysqlAutoPK.class.getName())){
         		continue;  
         	}else 
        	if(columnAnnotationMap.get(column).getName().equals(Id.class.getName())){
//        		System.out.println("长"+c2
        		if(isNull(o,column))  {
        			isId=true;
        		}
        	}else  if(isNull(o,column)){
        		continue;  
        	}
            if(i++ != 0)  
                sb.append(',');  
            sb.append(column);  
        }  
        return sb.toString();  
    }  
      
    /** 
     * 用于获取Insert的字段映射累加 
     * @return 
     */  
    public String returnInsertColumnsDefine(Object o) {  
        StringBuilder sb = new StringBuilder();  
        List<String> list = columnMap.get(o.getClass());  
        int i = 0;  
        for(String column : list) {
        	boolean isId=false;
//        	System.out.println("长"+columnAnnotationMap.get(column).getName());
        	if(columnAnnotationMap.get(column).getName().equals(MysqlAutoPK.class.getName())){
        		continue;
        		
        	}else
        	if(columnAnnotationMap.get(column).getName().equals(Id.class.getName())){
//        		System.out.println("长"+column);
        		if(isNull(o,column))  {
        			isId=true;
        		}else{
        			
        			try {
						newId=BeanUtils.getProperty(o, column);
					} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
        		}
        	}else  if(isNull(o,column)){
            	continue;  
            }
              
            if(i++ != 0)  
               sb.append(','); 
            if(isId){
            	newId=IdWorker.get50UUID();
            	isAutoId=true;
                sb.append("'"+newId+"'");  
//                newId=BeanUtils.copyProperty(o, name, value);
            }else{
            	sb.append("#{").append("pojo."+column).append('}');  
            }
        
        }  
       
        return sb.toString();  
    }  
    /**
     * 用于查询时返回的字段如：id,name,age
    * @Description: TODO(描述) 
    * @param  设定
    * @author 作者 jacking 
    * @date 2017-6-16 下午4:08:31 
    * @return
     */
    public String returnColumnsDefine(Object o) {  
        StringBuilder sb = new StringBuilder();  
        List<String> list = columnMap.get(o.getClass()); 
        int i = 0;  
        for(String column : list) {
            if(i++ != 0){
            	sb.append(','+column); 
            }else{
            	sb.append(column);  
            }
        }  
//        System.out.println("长"+sb.toString());
        return sb.toString();  
    } 
      
    /** 
     * 用于获取Update Set的字段累加 
     * @return 
     */  
    public String returnUpdateSet(Object o) {  
        StringBuilder sb = new StringBuilder();  
        List<String> list = columnMap.get(o.getClass());  
        int i = 0;  
        Map map=getAllField(o);
        for(String column : list) {
        	/*if(columnAnnotationMap.get(column).getName().equals(Id.class.getName())){
        		continue;  
        	}*/
        	if(map.get("objIdmysql")!=null&&map.get("objIdmysql").toString().equals(column)){
        		continue;  
        	}else
        	if(map.get("objId")!=null&&map.get("objId").toString().equals(column)){
        		continue;  
        	}
        	
        	
        	else if(isNull(o,column)) {
        		continue;  
        	}
            if(i++ != 0)  
                sb.append(',');  
            sb.append(column).append("=#{pojo.").append(column).append('}');  
        }  
        return sb.toString();  
    }  
      
      
    /** 
     * 打印类字段信息 
     */  
    @Override  
    public String toString() {  
        Field[] fields = o.getClass().getDeclaredFields();  
        StringBuilder sb = new StringBuilder();  
        sb.append('[');  
        for(Field f : fields) {  
            if(Modifier.isStatic(f.getModifiers()) || Modifier.isFinal(f.getModifiers()))  
                continue;  
            Object value = null;  
            try {  
                f.setAccessible(true);  
                value = f.get(this);  
            } catch (IllegalArgumentException e) {  
                e.printStackTrace();  
            } catch (IllegalAccessException e) {  
                e.printStackTrace();  
            }  
            if(value != null)  
                sb.append(f.getName()).append('=').append(value).append(',');  
        }  
        sb.append(']');  
          
        return sb.toString();  
    }  
    
    public static Map getAllField(Object o){
    	Map dataMap=new HashMap();
    	 Class tempClass =o.getClass();
    	   List<Field> fields = new ArrayList<>() ;
    	   String objId=null;
    	   String objIdmysql=null;
    	  while (tempClass != null&&!tempClass.getName().toLowerCase().equals("java.lang.object")) {//当父类为null的时候说明到达了最上层的父类(Object类).
         	Field fd[]=tempClass .getDeclaredFields();
         	fields.addAll(Arrays.asList(fd));
         	tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
         	for(Field field : fd){
         		Annotation an=field.getAnnotation(Id.class);
         		Annotation mysqlautoid=field.getAnnotation(MysqlAutoPK.class);
         		if(an!=null){
         			GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
         			if(gv==null||!gv.strategy().equals(GenerationType.IDENTITY)){
         				objId=field.getName();
         			}
         		}
         		if(mysqlautoid!=null){
         			objIdmysql=field.getName();
         		}
         	}
         }
    	  
    	  dataMap.put("fields", fields);
    	  dataMap.put("objId", objId);
    	  dataMap.put("objIdmysql", objIdmysql);
		return dataMap;
    }
    
    
      
    public static String getNewId() {
		return newId;
	}
	public static void setNewId(String newId) {
		MyBatisReflectUtil.newId = newId;
	}



	/** 
     * 以下为一些分页信息,如不需要可以删除 
     */  
    private int page;  
    private int pageSize;  
  
    public int getPage() {  
        return page;  
    }  
  
    public void setPage(int page) {  
        this.page = page;  
    }  
  
    public int getPageSize() {  
        return pageSize;  
    }  
  
    public void setPageSize(int pageSize) {  
        this.pageSize = pageSize;  
    }
	public static boolean isAutoId() {
		return isAutoId;
	}
	public static void setAutoId(boolean isAutoId) {
		MyBatisReflectUtil.isAutoId = isAutoId;
	}
	public static Map<Class<?>, List<String>> getColumnMap() {
		return columnMap;
	}
	public static void setColumnMap(Map<Class<?>, List<String>> columnMap) {
		MyBatisReflectUtil.columnMap = columnMap;
	}
	public boolean isAllField() {
		return isAllField;
	}
	public void setAllField(boolean isAllField) {
		this.isAllField = isAllField;
	}
	public static Map<String, Class<?>> getColumnAnnotationMap() {
		return columnAnnotationMap;
	}
	public static void setColumnAnnotationMap(Map<String, Class<?>> columnAnnotationMap) {
		MyBatisReflectUtil.columnAnnotationMap = columnAnnotationMap;
	}
	public static Object getO() {
		return o;
	}
	public static void setO(Object o) {
		MyBatisReflectUtil.o = o;
	}  
    
    
}  